package tianrun.ziguan.api.calculate.config.service.template.instance.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.springframework.stereotype.Service;
import tianrun.ziguan.api.calculate.config.constant.StringPools;
import tianrun.ziguan.api.calculate.config.dao.TIndicatorsInstanceMapper;
import tianrun.ziguan.api.calculate.config.dto.request.IndicatorsInstanceVO;
import tianrun.ziguan.api.calculate.config.dto.request.InstanceSelectionBody;
import tianrun.ziguan.api.calculate.config.dto.request.common.list.FilterField;
import tianrun.ziguan.api.calculate.config.dto.request.common.list.ListBody;
import tianrun.ziguan.api.calculate.config.dto.response.LabelSelectBody;
import tianrun.ziguan.api.calculate.config.entity.TGeModule;
import tianrun.ziguan.api.calculate.config.entity.TIndicatorsInstance;
import tianrun.ziguan.api.calculate.config.enums.MoldEnum;
import tianrun.ziguan.api.calculate.config.enums.SourceTypeEnum;
import tianrun.ziguan.api.calculate.config.enums.UsageAnalysisModuleEnum;
import tianrun.ziguan.api.calculate.config.service.common.CommonService;
import tianrun.ziguan.api.calculate.config.service.ge.TGeModuleService;
import tianrun.ziguan.api.calculate.config.service.template.instance.ITIndicatorsInstanceService;
import tianrun.ziguan.api.calculate.config.utils.CollectionUtil;
import tianrun.ziguan.api.calculate.config.utils.MapUtil;
import tianrun.ziguan.api.common.util.ListUtil;
import tianrun.ziguan.api.common.util.SpringContextUtil;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zhaoqi
 */
@Service
public class TIndicatorsInstanceServiceImpl extends ServiceImpl<TIndicatorsInstanceMapper, TIndicatorsInstance> implements ITIndicatorsInstanceService {

    private final TGeModuleService geModuleService;

    public TIndicatorsInstanceServiceImpl(TGeModuleService geModuleService) {
        this.geModuleService = geModuleService;
    }

    @Override
    public List<TIndicatorsInstance> listByModuleIds(Set<Long> ids) {
        if (CollectionUtil.isEmpty(ids)) {
            return Collections.emptyList();
        }
        return list(Wrappers.<TIndicatorsInstance>lambdaQuery().eq(TIndicatorsInstance::getIsValid, true).in(TIndicatorsInstance::getModuleId, ids));
    }

    @Override
    public List<IndicatorsInstanceVO> listVOByTemplateIds(Set<Long> ids) {
        if (CollectionUtil.isEmpty(ids)) {
            return Collections.emptyList();
        }
        return baseMapper.listByTemplateIds(ids);
    }

    @Override
    public Map<String, Set<String>> selectValue(InstanceSelectionBody body) {
        SourceTypeEnum sourceType = body.getSourceType();
        List<TGeModule> geModules = geModuleService.listByCType(sourceType);
        Map<String, Set<String>> hashMap = Maps.newHashMap();
        ArrayList<FilterField> filterFields = Lists.newArrayList(FilterField.equal(StringPools.VALID, 1), FilterField.equal(sourceType.getFiledName(), body.getSourceId()));
        CommonService commonService = SpringContextUtil.getBean(CommonService.class);
        geModules.forEach(geModule -> {
            List<Map<String, Object>> list = commonService.list(ListBody.of(filterFields, geModule.getTableName()));
            List<Object> id = list.stream().map(map -> map.get("id")).collect(Collectors.toList());
            if (ListUtil.isEmpty(id)) return;
            list = commonService.list(ListBody.of(Lists.newArrayList(FilterField.equal(StringPools.VALID, 1), FilterField.in(geModule.getInstanceParentIdField(), id)), geModule.getInstanceTableName()),false);
            Set<String> labels = list.stream().filter(beanMap -> !beanMap.containsKey("referenced") || Objects.equals(MapUtil.getBoolean(beanMap, "referenced"), true)).map(map -> MapUtil.getString(map, geModule.getCalLabelField())).filter(Objects::nonNull).collect(Collectors.toSet());
            if (ListUtil.isEmpty(labels)) return;

            if (Objects.equals(geModule.getMold(), MoldEnum.UsageAnalysis.name())) {
                labels = labels.stream()
                        .map(label -> Arrays.stream(UsageAnalysisModuleEnum.values()).map(e -> e.getLabel(label)).collect(Collectors.toSet()))
                        .flatMap(Collection::stream)
                        .collect(Collectors.toSet());
            }
            hashMap.put(geModule.getName(), labels);

        });
        return hashMap;
    }

    @Override
    public LabelSelectBody selectValueV2(InstanceSelectionBody body) {
        Map<String, Set<String>> selectMap = Maps.newHashMap();
        Map<String, String> moldMap = Maps.newHashMap();
        SourceTypeEnum sourceType = body.getSourceType();
        ArrayList<FilterField> filterFields = Lists.newArrayList(FilterField.equal(StringPools.VALID, 1), FilterField.equal(sourceType.getFiledName(), body.getSourceId()));
        CommonService commonService = SpringContextUtil.getBean(CommonService.class);

        List<TGeModule> geModules = geModuleService.listByCType(sourceType);
        geModules.forEach(geModule -> {
            moldMap.put(geModule.getMold(), geModule.getName());
            String idField = "id";
            ArrayList<String> fields = Lists.newArrayList(idField);
            List<Map<String, Object>> list = commonService.list(ListBody.of(filterFields, fields, geModule.getTableName()), false);
            List<Object> id = list.stream().map(map -> map.get("id")).collect(Collectors.toList());
            if (ListUtil.isEmpty(id)) return;
            list = commonService.list(ListBody.of(Lists.newArrayList(FilterField.equal(StringPools.VALID, 1), FilterField.in(geModule.getInstanceParentIdField(), id)), Arrays.asList("referenced", geModule.getCalLabelField()), geModule.getInstanceTableName()), false);
            Set<String> labels = list.stream().filter(beanMap -> !beanMap.containsKey("referenced") || Objects.equals(MapUtil.getBoolean(beanMap, "referenced"), true)).map(map -> MapUtil.getString(map, geModule.getCalLabelField())).filter(Objects::nonNull).collect(Collectors.toSet());
            if (ListUtil.isEmpty(labels)) return;

            if (Objects.equals(geModule.getMold(), MoldEnum.UsageAnalysis.name())) {
                labels = labels.stream()
                        .map(label -> Arrays.stream(UsageAnalysisModuleEnum.values()).map(e -> e.getLabel(label)).collect(Collectors.toSet()))
                        .flatMap(Collection::stream)
                        .collect(Collectors.toSet());
            }
            selectMap.put(geModule.getMold(), labels);
        });
        return new LabelSelectBody(selectMap, moldMap);
    }
}
